package com.tencent.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.entity.Result;
import com.tencent.filter.FormLoginFilter;
import com.tencent.filter.VerifyJWTFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;


/**
 * @BelongsProject: health2.2
 * @BelongsPackage: com.tencent.config
 * @ClassName: SecurityConfig
 * @Description: TODO
 * @Version: 1.0.0
 * @CreateTime: 2022-08-30  10:52
 * @Author: Yangjx
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //开跨站访问控制,且允许帧标签展示内容
        http.csrf().disable().headers().frameOptions().sameOrigin();
//        http.csrf().disable();

        //设置跨域访问
        http.cors().configurationSource(getConfigSource());

        //添加/login请求的过滤器.内部是通过UsernamePasswordAuthenticationFilter完成
        http.addFilter(new FormLoginFilter(authenticationManager()))
                .addFilter(new VerifyJWTFilter(authenticationManager()));

        //不需要登录的资源,不拦截,允许访问/resources/static
        http.authorizeRequests()
                //   .antMatchers("/orderhistory/**").authenticated()
                .antMatchers("/css/**",
                        "/fonts/**",
                        "/img/**",
                        "/js/**",
                        "/plugins/**",
                        "/index.html",
                        "/orderhistory/**").permitAll();


        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            //当访问的资源需要登录，而现在又没有登录时，会执行这个端点对象的commence方法
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException, IOException {
                //在这个方法中，需要向前端项目中响应一个未登录的信息
                Result result = Result.noLogin("请先登录 --yjx");
                ObjectMapper om = new ObjectMapper();
                String json = om.writeValueAsString(result);

                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write(json);
            }
        }).accessDeniedHandler(new AccessDeniedHandler() {
            @Override
            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                //在这个方法中，需要向前端项目中响应一个没有权限的信息
                Result result = Result.noAuth("无权访问");
                ObjectMapper om = new ObjectMapper();
                String json = om.writeValueAsString(result);

                response.setContentType("text/html;charset=utf-8");
                response.getWriter().write(json);
            }
        });


        //设置哪些资源需要登录，哪些资源需要权限
//        http.authorizeRequests()
//                .antMatchers(//"/health-index.html",
//                        "/health-setmeal.html",
//                        "/health-report.html",
//                        "/health-risk.html",
//                        "/health-intervention.html",
//                        "/health-record.html",
//                        "/health-information.html").authenticated()//需要登录,拦截
//                .antMatchers().hasRole("P1")
//                .antMatchers("/**").permitAll();

        //禁止session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

    /**
     * @return CorsConfigurationSource
     * @Description: TODO 跨域访问的配置源
     * @author Yangjx
     * @date 2022/8/30 11:23
     */
    private CorsConfigurationSource getConfigSource() {
        //基于路径的同源匹配方式
        UrlBasedCorsConfigurationSource urlSource = new UrlBasedCorsConfigurationSource();

        CorsConfiguration config = new CorsConfiguration();
        // *  表示允许任何服务器来访问我的资源
        config.setAllowedOrigins(Arrays.asList("http://localhost"));
        // * 允许所有请求方式的跨域访问 默认只支持get请求
        config.setAllowedMethods(Arrays.asList("*"));
        // * 允许所有头信息的携带
        config.setAllowedHeaders(Arrays.asList("*"));
        //设置为ture，表示允许携带cookie认证信息（这个值一旦设置为true，origin的设置不允许在使用*了）
        config.setAllowCredentials(true);
        //  /** 表示所有这种路径的访问，都匹配这个同源设置
        urlSource.registerCorsConfiguration("/**", config);//可以写多次,配置不同的访问路径

        return urlSource;
    }
}

